#include "udp_pipe.h"
#include "event2/event.h"
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <QDebug>

using namespace std;

UDPPipe::UDPPipe(int listen_port, int send_port, const char* dest_host, int dest_port)
    : listen_port_(listen_port),
      send_port_(send_port),
      dest_port_(dest_port),
      eb_(NULL)
{
    memset(dest_host_, 0, 16);
    memcpy(dest_host_, dest_host, strlen(dest_host));
    buf_ = new char[65535];
}

UDPPipe::~UDPPipe()
{
    if(buf_)
    {
        delete[] buf_;
    }
    if(recv_ev_)
    {
        event_del(recv_ev_);
        event_free(recv_ev_);
        recv_ev_ = NULL;
    }
}

void UDPPipe::Init()
{
    if(!this->eb_)
    {
        qCritical("event_base未被初始化");
        return;
    }
    listen_sock_ = socket(AF_INET, SOCK_DGRAM, 0);
    sockaddr_in  sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(listen_port_);
    bind(listen_sock_, (sockaddr*)&sin, sizeof(sin));
    recv_ev_ = event_new(this->eb_, listen_sock_, EV_READ | EV_PERSIST, OnRead, this);
    event_add(recv_ev_, 0);

    send_sock_ = socket(AF_INET, SOCK_DGRAM, 0);
    sockaddr_in from, to;
    memset(&from, 0, sizeof(from));
    from.sin_addr.s_addr = INADDR_ANY;
    from.sin_family = AF_INET;
    from.sin_port = htons(send_port_);
    bind(send_sock_, (sockaddr*)&from, sizeof(from));
    memset(&to, 0, sizeof(to));
    to.sin_addr.s_addr = inet_addr(dest_host_);
    to.sin_family = AF_INET;
    to.sin_port = htons(dest_port_);
    connect(send_sock_, (const sockaddr*)&to, sizeof(to));
    qInfo("监听端口%d，发送端口%d，目标主机%s:%d", listen_port_, send_port_, dest_host_, dest_port_);
}

void UDPPipe::OnRead(int fd, short what, void *cbarg)
{
    UDPPipe* self = (UDPPipe*)cbarg;
    int len = read(fd, self->buf_, 65535);
    if(len > 0)
    {
        self->buf_[len] = '\0';
        send(self->send_sock_, self->buf_, len, 0);
    }
}

void UDPPipe::set_event_base(event_base *eb)
{
    this->eb_ = eb;
}
